package org.example.service;

/**
 * @BelongsProject: Dynamic-relationship-binding
 * @BelongsPackage: org.example.service
 * @Author: dengxiyan
 * @CreateTime: 2025/07/04  10:57
 * @Description: TODO
 * @Version: 1.0
 */
import org.example.config.RelationConfig;
import org.example.exceptin.EntityNotFoundException;
import org.example.model.BaseEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public abstract class GenericEntityService<T extends BaseEntity> implements EntityService<T> {

    @Autowired
    private DynamicRelationManager relationManager;

    protected abstract JpaRepository<T, Long> getRepository();

    @Override
    @Transactional
    public T save(T entity) {
        return getRepository().save(entity);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        getRepository().deleteById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public T findById(Long id) {
        Optional<T> entity = getRepository().findById(id);
        if (entity.isPresent()) {
            relationManager.loadRelations(entity.get());
            return entity.get();
        }
        return null;
    }

    @Override
    @Transactional(readOnly = true)
    public Page<T> findAll(Pageable pageable) {
        Page<T> page = getRepository().findAll(pageable);
        page.getContent().forEach(relationManager::loadRelations);
        return page;
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> findAll() {
        List<T> entities = getRepository().findAll();
        entities.forEach(relationManager::loadRelations);
        return entities;
    }

    @Override
    @Transactional
    public T addRelation(Long sourceId, Long targetId, String relationField) {
        T source = getRepository().findById(sourceId)
                .orElseThrow(() -> new EntityNotFoundException("Source entity not found with id: " + sourceId));
        Object target = findTargetEntity(targetId, relationField);

        if (target != null) {
            relationManager.addRelation(source, target);
            getRepository().save(source); // 保存更新后的实体
        }

        return source;
    }

    @Override
    @Transactional
    public void removeRelation(Long sourceId, Long targetId) {
        T source = getRepository().findById(sourceId)
                .orElseThrow(() -> new EntityNotFoundException("Source entity not found with id: " + sourceId));
        Object target = findTargetEntity(targetId, "any"); // 实际实现中需要更精确

        if (target != null) {
            relationManager.removeRelation(source, target);
            getRepository().save(source);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Page<Object> findRelatedEntities(Long id, String relationField, Pageable pageable) {
        T entity = getRepository().findById(id)
                .orElseThrow(() -> new EntityNotFoundException("entity not found with id: " + id));
        return relationManager.findRelatedEntities(entity, relationField, pageable);
    }

    // 根据关系字段找到目标实体类并加载实体
    private Object findTargetEntity(Long targetId, String relationField) {
        // 获取当前服务管理的实体类
        Class<T> managedClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];

        // 从关系管理器中获取当前实体类的关系配置
        Map<String, RelationConfig.RelationDefinition> relations = relationManager
                .getRelationDefinitions(managedClass);

        if (relations == null || !relations.containsKey(relationField)) {
            throw new IllegalArgumentException("Unknown relation field '" + relationField +
                    "' for entity " + managedClass.getSimpleName());
        }

        RelationConfig.RelationDefinition rd = relations.get(relationField);
        try {
            // 根据配置的目标实体类型查找对应的服务
            EntityService<?> targetService = relationManager
                    .getServiceForEntity(rd.getTarget());

            // 调用服务查找目标实体
            return targetService.findById(targetId);
        } catch (Exception e) {
            throw new RuntimeException("Failed to find target entity for relation '" +
                    relationField + "'", e);
        }
    }
}
